package com.yhx.share.thisShare;
import com.alibaba.fastjson.JSON;

import org.apache.commons.lang.StringUtils;
import org.bouncycastle.util.encoders.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @Author: wangchunwei8
 * @CreateTime: 2020-09-22 17:26
 * @Description: RSA加解密工具类  密钥不要带换行符
 */
public class RSAUtils11 {

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    private static final String RSA="RSA";

    private static final String RSA1="RSA/ECB/PKCS1Padding";

    /**
     * 私钥解密
     * @param data  密文
     * @param key  私钥
     * @return  明文
     */
    public static byte[] decryptByPrivateKeyFromString(String data, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
        if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
            throw new RuntimeException("RSA私钥解密参数非法");
        }
        //先base64解码
        return decryptByPrivateKey(Base64.decode(data), key);
    }
    /**
     * 私钥解密
     * @param data  密文
     * @param key  私钥
     * @return  明文
     */
    public static byte[] decryptByPrivateKey(byte[] data, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
        if (data==null || StringUtils.isBlank(key)) {
            throw new RuntimeException("RSA私钥解密参数非法");
        }
        PrivateKey privateKey = buildPrivateKey(key);
        Cipher cipher = Cipher.getInstance(RSA1);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    private static PrivateKey buildPrivateKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        byte[] keyBuffer = Base64.decode(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBuffer);
        return keyFactory.generatePrivate(keySpec);
    }
    /**
     * 公钥解密
     * @param data  密文
     * @param key   公钥
     * @return  明文
     */
    public static byte[] decryptByPublicKeyFromString(String data, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
        if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
            throw new RuntimeException("RSA公钥解密参数非法");
        }
        //先base64解码
        return decryptByPublicKey(Base64.decode(data), key);
    }
    /**
     * 公钥解密
     * @param data  密文
     * @param key   公钥
     * @return  明文
     */
    public static byte[] decryptByPublicKey(byte[] data, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
        if (data==null || StringUtils.isBlank(key)) {
            throw new RuntimeException("RSA公钥解密参数非法");
        }
        PublicKey publicKey = buildPublicKey(key);
        Cipher cipher = Cipher.getInstance(RSA1);
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    private static PublicKey buildPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        byte[] keyBuffer = Base64.decode(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBuffer);
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 私钥加密
     * @param data  明文
     * @param key  私钥
     * @return  密文
     */
    public static byte[] encryptByPrivateKey(String data, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
        if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
            throw new RuntimeException("RSA私钥加密参数非法");
        }
        return encryptByPrivateKey(data.getBytes(StandardCharsets.UTF_8), key);
    }
    /**
     * 私钥加密
     * @param data  明文
     * @param key  私钥
     * @return  密文
     */
    public static String encryptByPrivateKeyToString(String data, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
        if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
            throw new RuntimeException("RSA私钥加密参数非法");
        }
        //base64编码
        return Base64.toBase64String(encryptByPrivateKey(data.getBytes(StandardCharsets.UTF_8), key));
    }

    public static byte[] encryptByPrivateKey(byte[] data, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
        PrivateKey privateKey = buildPrivateKey(key);
        Cipher cipher = Cipher.getInstance(RSA1);
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥加密
     * @param data  明文
     * @param key  公钥
     * @return  密文
     */
    public static byte[] encryptByPublicKey(byte[] data, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
        PublicKey publicKey = buildPublicKey(key);
        Cipher cipher = Cipher.getInstance(RSA1);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥加密
     * @param data  明文
     * @param key  公钥
     * @return  密文
     */
    public static byte[] encryptByPublicKey(String data, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
        if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
            throw new RuntimeException("RSA公钥加密参数非法");
        }
        return encryptByPublicKey(data.getBytes(StandardCharsets.UTF_8), key);
    }
    /**
     * 公钥加密
     * @param data  明文
     * @param key  公钥
     * @return  密文
     */
    public static String encryptByPublicKeyToString(String data, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
        return Base64.toBase64String(encryptByPublicKey(data.getBytes(StandardCharsets.UTF_8), key));
    }

    /**
     * 数据分段加解密
     * @param cipher
     * @param data
     * @return
     */
    public static byte[] getBlockDeal(Cipher cipher,byte[] data,int length) throws BadPaddingException, IllegalBlockSizeException {
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > length) {
                cache = cipher.doFinal(data, offSet, length);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * length;
        }
        return out.toByteArray();
    }
    public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
        String privateKey="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAO39/7S8D+3p3RJ8" +
                "npTPi6rnUlHA/t8saQGrPQZ79jKrFPP28b2Lqy15y3znZdN3NArCtOWHx+276On+" +
                "dedLQHTKIA5aQ2bekOQX7neNbbe/yC+/sAIQ2UP0cCOpmaanFAdpKaSmcLNXimFX" +
                "mdh8XFMojaB6Uo8idMkhI5Sd2XizAgMBAAECgYBKrhqQRzcka+9QPsSwY5QrM91U" +
                "BCC2PURSHr7OixWNfrvbdlETLoGvinl9H0uHmO8+tSx4nivxgLasvomW47k8kco0" +
                "y85GtdwDapQ7vxU8IFtedfndFhLOdAnKB35ymyhA2EHT2+hdsnV2dY/kJQqnfzdx" +
                "X0was/jKtKFBTSrFeQJBAPjdY3D2A/UTQgMKVvoZLUwK7JHKkn2o2X7feYF4YO23" +
                "ZS1GT7snwjsFZP/EjkKV2JicVa+B1+ceEZwBeN2nLqUCQQD00M7P61MNG994K8Nr" +
                "senGKn+y4+Q3dWxA9JYsdL/ozeBOs5dFodPvR72tiRwa/jpnuQSy68dG2OfTqGbi" +
                "N4J3AkEAjvv0JHTU9TwpU0HfkzZf9i7YmTNAU35t6B1R3HdjiXEzan3ZVXiUegCx" +
                "dNpjuhIKLjS0bnA1sg5uo6mc3g0uGQJAK0em6DcQDac50ILcH3PqgjANN1D2jZ9i" +
                "rfEPg3h4XO3Yk9FIEvVTBGBIdh9hKpx7Ms8Qt5jbN/ksssx4s9FgbQJADv0ShQr2" +
                "qlcTAslzMk6Tf+RAT2+Z15M5EszwIX4yi13X2CLxL1TZzeMnfjztzleTJ6mQ901p" +
                "C/OJO67T7ALX7w==";
        String publicKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDt/f+0vA/t6d0SfJ6Uz4uq51JR" +
                "wP7fLGkBqz0Ge/YyqxTz9vG9i6stect852XTdzQKwrTlh8ftu+jp/nXnS0B0yiAO" +
                "WkNm3pDkF+53jW23v8gvv7ACENlD9HAjqZmmpxQHaSmkpnCzV4phV5nYfFxTKI2g" +
                "elKPInTJISOUndl4swIDAQAB";

        String data="wangchunweiwangchunweiwangchunweiwangchunweiwangchunweiwangchunweiwangchunweiwangchunweiwangchunweiwangchunweiwangchunweiwangchunwei";
       //*私钥加密，公钥解密*//*
        String miwen=encryptByPrivateKeyToString(data,privateKey);
        System.out.println(miwen);
        String mingwen=new String(decryptByPublicKeyFromString(miwen,publicKey), StandardCharsets.UTF_8);
        System.out.println(mingwen);

        /*公钥加密，私钥解密
        String miwen=encryptByPublicKeyToString(JSON.toJSONString(RequestInfo),publicKey);
        System.out.println(miwen);
        String mingwen=new String(decryptByPrivateKeyFromString(miwen,privateKey), StandardCharsets.UTF_8);
        System.out.println(mingwen);*/
    }
}
